package rpc

import (
	"errors"
	"fmt"
	"gitee.com/injoyai/goutil/net/tcp/callback"
	"sync"
)

// Server
// 采用长连接,客户端建立连接之后会复用改连接
// 远程地址不同会有多个客户端,
// 相同的远程地址也可以通过编号来建立多个客户端
type Server struct {
	*callback.Server
	Handle  map[string]func(*callback.Msg)
	BindErr func(*callback.Msg, error)
	mu      sync.RWMutex
}

// NewServer 新建rpc服务端
// @port,端口
// @limit,同时处理数量
func NewServer(port int, limit ...uint) *Server {
	data := &Server{
		Handle: make(map[string]func(*callback.Msg)),
	}
	data.Server = callback.NewServer(port, data.rpcServer, limit...)
	return data
}

// SetBindErr 设置自定义错误处理
func (this *Server) SetBindErr(fn func(*callback.Msg, error)) *Server {
	this.BindErr = fn
	return this
}

//rpc服务
func (this *Server) rpcServer(msg *callback.Msg) {
	this.mu.RLock()
	fn, ok := this.Handle[msg.MsgType]
	this.mu.RUnlock()
	if ok && fn != nil {
		defer func() {
			if e := recover(); e != nil {
				err := errors.New(fmt.Sprint(e))
				if this.BindErr != nil {
					this.BindErr(msg, err)
				} else {
					msg.SetErr(err)
				}
			}
		}()
		fn(msg)
	} else {
		msg.SetErr(errors.New("远程方法未注册"))
	}
}

// Debug 调试模式,打印底层数据
func (this *Server) Debug(b ...bool) *Server {
	this.Server.Debug(b...)
	return this
}

// Bind 路路由注册
func (this *Server) Bind(s string, fn func(*callback.Msg)) *Server {
	this.mu.Lock()
	defer this.mu.Unlock()
	this.Handle[s] = fn
	return this
}

// Run 运行
func (this *Server) Run() error {
	return this.Server.Run()
}

/*



 */

// NewClient
// 新建客户端,相同远程地址客户端复用,多个客户端(相同远程地址)通过num来增加
// @addr,远程地址,例如:127.0.0.1:10086
// @num,客户端编号,多个编号进行多个远程连接
func NewClient(addr string, num ...int) *callback.Client {
	return callback.NewClient(addr, num...)
}

// Send 发送数据
// @addr,远程地址,例如:127.0.0.1:10086
// @msgType,消息类型,
// @msg,消息内容,结构默认转json格式
// @num,客户端编号,多个编号进行多个远程连接
func Send(addr, msgType string, msg interface{}, num ...int) *callback.Msg {
	return NewClient(addr, num...).Send(msgType, msg)
}
